package com.ar4j.handler;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;

import org.antlr.stringtemplate.StringTemplate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import net.sf.cglib.proxy.MethodProxy;

import com.ar4j.ActiveRecordContext;
import com.ar4j.ActiveRecordMetadata;
import com.ar4j.sql.ExtendedMapSqlParameterSource;
import com.ar4j.sql.SqlUtils;

/**
 * A handler for active record find operations
 */
public class CountMethodHandler extends NoOpMethodHandler {
  private static final StringTemplate QUERY_TEMPLATE = new StringTemplate(
      "SELECT COUNT(*) FROM $qualifiedTable$ T $where$"
    ); 
  
  @SuppressWarnings("unchecked")
  @Override
  public Object intercept(ActiveRecordMetadata metadata, ActiveRecordContext context, Object target, Method method, Object[] args, MethodProxy proxy) 
    throws Throwable {
    
    // make sure we have a template first
    if(context.getSimpleTemplate() == null) {
      throw new IllegalStateException("Cannot execute count on an active record that does not have a datasource set");
    }
    
    // build field list and
    Map<String, Object> parameters = (Map<String, Object>) args[0];
    Collection<String> fields = new HashSet<String>();
    Collection<String> collectionFields = new HashSet<String>();
    HandlerUtils.scanParametersForFields(parameters, metadata, fields, collectionFields);
    
    // build parameters and get query
    ExtendedMapSqlParameterSource source = new ExtendedMapSqlParameterSource(parameters, metadata.getPropertyTypeConvertorMap());
    String sql = HandlerUtils.renderQueryWithWhere(QUERY_TEMPLATE, 
        metadata, 
        context, 
        SqlUtils.composeWhereClause(fields, collectionFields, "T", metadata.getPropertyColumnNameMap()));
        
    return context.getSimpleTemplate().queryForLong(sql, source);
  }

  @Override
  public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
  }
  
}
